package com.toivan.demo;

import android.content.ContentValues;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.net.Uri;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.MediaStore;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.toivan.demo.databinding.ActivityCameraBinding;
import com.toivan.mt.utils.MtSharedPreferences;
import com.toivan.mt.views.MtBeautyPanel;
import com.toivan.sdk.MtPictureRenderer;
import com.toivan.sdk.MtPreviewRenderer;
import com.toivan.sdk.MtSDK;
import com.toivan.sdk.egl.MtGLUtils;
import com.toivan.sdk.model.MtRotation;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class CameraActivity extends AppCompatActivity implements GLSurfaceView.Renderer, View.OnClickListener {

    private ActivityCameraBinding binding;
    private GLSurfaceView glSurfaceView;
    private ImageView switchCam;
    private ImageView capture;
    private MtCamera camera;
    private SurfaceTexture surfaceTexture;
    private int textureId;
    private boolean isFrontCamera = true;
    private boolean isCameraSwitched;
    private boolean isRenderInit;
    private MtRotation mtRotation;
    private MtPreviewRenderer previewRenderer;
    private int previewWidth = 1280, previewHeight = 720;
    private int pictureWidth = 720, pictureHeight = 1280;
    private int surfaceWidth, surfaceHeight;
    private MtPictureRenderer pictureRenderer;
    private HandlerThread pictureHandlerThread;
    private Handler pictureHandler;
    private boolean isTakingPic;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityCameraBinding.inflate(getLayoutInflater());

        View view = binding.getRoot();
        setContentView(view);

        addContentView(new MtBeautyPanel(this).init(MtSDK.get()),
                new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        camera = new MtCamera(this);

        glSurfaceView = binding.glSurfaceView;
        glSurfaceView.setEGLContextClientVersion(2);
        glSurfaceView.setRenderer(this);
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        pictureHandlerThread = new HandlerThread("TakePicture");
        pictureHandlerThread.start();
        pictureHandler = new Handler(pictureHandlerThread.getLooper());

        switchCam = binding.switchCam;
        capture = binding.capture;
        switchCam.setOnClickListener(this);
        capture.setOnClickListener(this);

    }

    @Override
    protected void onResume() {
        super.onResume();
        try {
            camera.startPreview();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        try {
            camera.stopPreview();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        MtSDK.get().destroyRenderTextureOES();
        isRenderInit = false;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        textureId = MtGLUtils.getExternalOESTextureID();
        surfaceTexture = new SurfaceTexture(textureId);
        surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
            @Override
            public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                glSurfaceView.requestRender();
            }
        });
        int cameraId = isFrontCamera ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
        mtRotation = isFrontCamera ? MtRotation.CLOCKWISE_270 : MtRotation.CLOCKWISE_90;
        camera.openCamera(cameraId, previewWidth, previewHeight);
        camera.setPreviewSurface(surfaceTexture);
        camera.startPreview();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        surfaceWidth = width;
        surfaceHeight = height;
        previewRenderer = new MtPreviewRenderer(surfaceWidth, surfaceHeight);
        previewRenderer.create(isFrontCamera);
        pictureRenderer = new MtPictureRenderer(pictureWidth, pictureHeight);
        pictureRenderer.create(isFrontCamera);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        if (isCameraSwitched) {
            MtSDK.get().destroyRenderTextureOES();
            isRenderInit = false;
            isCameraSwitched = false;
        }
        if (!isRenderInit) {
            MtSDK.get().destroyRenderTextureOES();
            MtSharedPreferences.getInstance().initAllSPValues(CameraActivity.this);
            isRenderInit = MtSDK.get().initRenderTextureOES(previewWidth, previewHeight, mtRotation, isFrontCamera, 5);
        }
        int oesTextureId = MtSDK.get().renderTextureOES(textureId);
        previewRenderer.render(oesTextureId);

        if (isTakingPic) {
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(pictureWidth * pictureHeight * 4);
            byteBuffer.order(ByteOrder.nativeOrder());
            byteBuffer.position(0);
            pictureRenderer.takePicture(oesTextureId, byteBuffer);
            saveBitmap(pictureWidth, pictureHeight, byteBuffer);
            isTakingPic = false;
        }

        surfaceTexture.updateTexImage();
    }

    private void saveBitmap(final int width, final int height, final ByteBuffer byteBuffer) {
        pictureHandler.post(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                bitmap.copyPixelsFromBuffer(byteBuffer);

                String picName = "MENG_" + System.currentTimeMillis() + ".jpg";
                if (Build.VERSION.SDK_INT >= 29) {
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Images.Media.DISPLAY_NAME, picName);
                    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
                    values.put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/Toivan");

                    Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                    if (uri != null) {
                        try {
                            OutputStream os = getContentResolver().openOutputStream(uri);
                            if (os != null) {
                                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);
                                os.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, picName, null);
                    sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE));
                }
                bitmap.recycle();
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.switchCam:
                switchCamera();
                break;
            case R.id.capture:
                takePicture();
                break;
        }
    }

    private void takePicture() {
        isTakingPic = true;
    }

    private void switchCamera() {
        isFrontCamera = !isFrontCamera;
        isCameraSwitched = true;
        glSurfaceView.queueEvent(new Runnable() {
            @Override
            public void run() {
                previewRenderer = new MtPreviewRenderer(surfaceWidth, surfaceHeight);
                previewRenderer.create(isFrontCamera);
                pictureRenderer = new MtPictureRenderer(pictureWidth, pictureHeight);
                pictureRenderer.create(isFrontCamera);

                textureId = MtGLUtils.getExternalOESTextureID();
                surfaceTexture = new SurfaceTexture(textureId);
                surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
                    @Override
                    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                        glSurfaceView.requestRender();
                    }
                });

                int cameraId = isFrontCamera ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
                mtRotation = isFrontCamera ? MtRotation.CLOCKWISE_270 : MtRotation.CLOCKWISE_90;
                camera.releaseCamera();
                camera.openCamera(cameraId, previewWidth, previewHeight);
                camera.setPreviewSurface(surfaceTexture);
                camera.startPreview();
            }
        });
    }

}
